#include "amf.h"
#include "umapi_libc.h"

#define NEWAMFValue(r_r) \
	AMFValue * r_r = (AMFValue *)umapi_malloc(sizeof(AMFValue));\
	r_r->as_string = asString;\
	r_r->as_number = asNumber; \
	r_r->as_integer = asInter; \
	r_r->as_bool = asBool; \
	r_r->as_object = asObject; \
	r_r->clear = clear; \
	r_r->type = getType; \
	r_r->get = getAMFValue; \
	r_r->set = setAMFValue; \
	r_r->free = AMFValuefree; 

UM_VOID freeAmfObject(amf_object_t* object)
{
	if(!object)
		return ;
	struct umapi_list_head *pos, *n;
	umapi_list_for_each_safe(pos,n, &object->head){
		AMFObject *i = umapi_list_entry(pos, AMFObject, head);
		umapi_list_del(&i->head);
		if(i->first)
			umapi_free(i->first);
		if(i->second)
		{
			if(i->second->m_type == AMF3_OBJECT)
			{
				freeAmfObject(&i->second->m_value.object);
			}
			i->second->free(i->second);
		}
		umapi_free(i);
	}
}
UM_VOID initAmfObject(amf_object_t** object)
{
	amf_object_t* ret = (amf_object_t*)umapi_malloc(sizeof(amf_object_t));
	umapi_list_create(&ret->head);
	*object = ret;
}
UM_VOID* clear(AMFValue * value)
{
	switch (value->m_type) {
	case AMF_STRING:
		umapi_free(value->m_value.string);
		break;
	case AMF_OBJECT:
	case AMF_ECMA_ARRAY:
		freeAmfObject(value->m_value.object);
		umapi_free(value->m_value.object);
		break;
	case AMF_NULL:
	case AMF_NUMBER:
	case AMF_INTEGER:
	case AMF_BOOLEAN:
	case AMF_UNDEFINED:
		break;
	}
}
static UM_CHAR * asString(AMFValue *value)
{
	assert(value->m_type == AMF_STRING);
	return value->m_value.string;
}
static UM_DOUBLE asNumber(AMFValue *value)
{
	assert(value->m_type == AMF_NUMBER);
	return value->m_value.number;

}
static UM_DOUBLE asInter(AMFValue *value)
{
	assert(value->m_type == AMF_INTEGER);
	return value->m_value.integer;
}
static UM_BOOL asBool(AMFValue *value)
{
	assert(value->m_type == AMF_BOOLEAN);
	return value->m_value.boolean;
}
static amf_object_t *asObject(AMFValue *value)
{
	assert(value->m_type == AMF_OBJECT  || AMF_ECMA_ARRAY == value->m_type);
	return value->m_value.object;
}
static AMFType getType(AMFValue *value)
{
	return value->m_type;
}
static UM_VOID* getAMFValue(AMFValue * ptr, AMFType t, UM_CHAR *k, UM_VOID* value)
{
	if(!ptr->m_value.object)
		return UM_NULL;
	struct umapi_list_head *pos, *n;
	umapi_list_for_each_safe(pos,n, &ptr->m_value.object->head){
		AMFObject *i = umapi_list_entry(pos, AMFObject, head);
		if(umapi_strcmp(i->first, k) == 0)
		{
			AMFValue * ret = i->second;
			switch(t)
			{
				case AMF_STRING:
					{
						UM_CHAR ** pValue = (UM_CHAR **)value;
						*pValue = ret->as_string(ret);
					}
					break;
				case AMF_NUMBER:
					{
						UM_DOUBLE *d =  (UM_DOUBLE *)value;
						*d = ret->as_number(ret);
						break;
					}
				case AMF_OBJECT:
					{
						amf_object_t ** pValue = (amf_object_t *)value;
						* pValue = ret->as_object(ret);
					}
					break;
				case AMF_INTEGER:
					{
						UM_S32 *pValue = (UM_S32 *)value;
						*pValue = ret->as_integer(ret);
						break;
					}
			}
			return value;
		}
	}
	return UM_NULL;
}
static UM_VOID setAMFValue(AMFValue * ptr, AMFType t, UM_CHAR *k ,UM_VOID *value)
{
	AMFObject *o = (AMFObject*)umapi_malloc(sizeof(AMFObject));
	o->first = (UM_CHAR*)umapi_malloc(umapi_strlen(k) + 1);
	umapi_sprintf(o->first, "%s", k);
	switch(t)
	{
		case AMF_STRING:
			o->second = AMFValueFromChar((UM_CHAR *)value);
			break;
		case AMF_NUMBER:
			o->second = AMFValueFromDouble(*(UM_DOUBLE*)value);
			break;
		case AMF_OBJECT:
			o->second = AMFValueFromObject((amf_object_t *)value);
			break;
		case AMF_INTEGER:
			o->second = AMFValueFromInt(*(UM_S32*)value);
			break;
	}
	//o->second = value;
	umapi_list_add(&o->head, &ptr->m_value.object->head);
	return ;
}

static UM_VOID AMFValuefree(AMFValue *value)
{
	value->clear(value);
	umapi_free(value);
}


AMFValue *AMFValueFromDefault(AMFType type)
{
	NEWAMFValue(ret);
	ret->m_type = type;
	switch (type) {
	case AMF_OBJECT:
	case AMF_ECMA_ARRAY:
		initAmfObject(&ret->m_value.object);
		break;
	case AMF_NUMBER:
	case AMF_INTEGER:
	case AMF_NULL:
	case AMF_UNDEFINED:
		break;
	default:
		return UM_NULL;
	}
	return ret;
}

AMFValue* AMFValueFromChar(UM_CHAR *s)
{
	NEWAMFValue(ret);
	ret->m_type = AMF_STRING;
	ret->m_value.string = (UM_CHAR *)umapi_malloc(umapi_strlen(s) + 1);
	umapi_sprintf(ret->m_value.string, "%s", s);
	return ret;
}

AMFValue* AMFValueFromDouble(UM_DOUBLE n)
{
	NEWAMFValue(ret);
	ret->m_type = AMF_NUMBER;
	ret->m_value.number = n;
	return ret;
}

AMFValue* AMFValueFromInt(UM_S32 i)
{
	NEWAMFValue(ret);
	ret->m_type = AMF_INTEGER;
	ret->m_value.integer = i;
	return ret;
}

AMFValue* AMFValueFromBool(UM_BOOL b)
{
	NEWAMFValue(ret);
	ret->m_type = AMF_BOOLEAN;
	ret->m_value.boolean = b;
	return ret;
}

AMFValue* AMFValueFromObject(amf_object_t *object)
{
	NEWAMFValue(ret);
	ret->m_type = AMF_OBJECT;
	ret->m_value.object = object;
	return ret;
}

AMFValue* AMFValueClone(AMFValue *from)
{
	NEWAMFValue(ret);
	umapi_memcpy(ret, from,sizeof(AMFValue));
	return ret;
}


